package com.cmit.upay.monitor.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.IOException;
import java.io.StringWriter;

/**
 * {@code JsonUtil}主要区分普通类型和泛型两种。
 * <p>
 * 提供将类(包括泛型)与json字符串互转的方法；
 * <p>
 * 从json字符串内部提取出内部的bean的方法；
 * <p>
 * 更新json字符串内部bean字符串的方法。
 *
 * @author liyuanchang, wuhang
 * 应强化Json序列化与反序列化的功能，但不推荐使用本工具类，建议直接使用Jackson或JsonPath提供的API
 */
public class JsonUtil {
    
    private static final ObjectMapper MAPPER = new ObjectMapper();
    
    /**
     * 判断字符串中是否包含Json格式字符串
     *
     */
    public static boolean isJsonStr(String str) {
        try {
            MAPPER.readTree(str);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    
    /**
     * 将JavaBean将转换为Json字符串
     *
     * @param obj - java对象
     *
     */
    public static String object2JsonStr(Object obj) {
        String jsonStr;
        try {
            jsonStr = MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return jsonStr;
    }
    
    /**
     * 将JSON格式的字符串转为JavaBean
     *
     */
    public static <T> T jsonStr2Obj(String json, Class<T> clazz) {
        T obj;
        try {
            obj = MAPPER.readValue(json, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }
    
    /**
     * 从 json里获取内部bean
     *
     */
    public static <T> T get(String json, String fieldName, Class<T> clazz) {
        T obj;
        try {
            ObjectNode objectNode = (ObjectNode) MAPPER.readTree(json);
            JsonNode node = objectNode.get(fieldName);
            if (node == null) {
                return null;
            }
            obj = MAPPER.readValue(node.toString(), clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }
    
    /**
     * 从 json里获取内部bean
     *
     * @param json         json字符串
     * @param fieldName    属性名
     * @param valueTypeRef 类型，eg:new TypeReference&lt;List&lt;ChargeQueryBean&gt;&gt;(){}
     *
     */
    public static <T> T get(String json, String fieldName, TypeReference<?> valueTypeRef) {
        T obj;
        try {
            ObjectNode objectNode = (ObjectNode) MAPPER.readTree(json);
            JsonNode node = objectNode.get(fieldName);
            if (node == null) {
                return null;
            }
            obj = MAPPER.readValue(node.toString(), valueTypeRef);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }
    
    /**
     * 将新json字符串更新到json字符串中
     *
     * @param json         原json字符串
     * @param needToUpdate 新字符串
     * @param fieldName    属性名
     *
     */
    public static String updateJsonStr(String json, String needToUpdate, String fieldName) {
        ObjectNode objectNode = null;
        try {
            objectNode = (ObjectNode) MAPPER.readTree(json);
            JsonNode needToUpdateNode = MAPPER.readTree(needToUpdate);
            objectNode.set(fieldName, needToUpdateNode);
            json = objectNode.toString();
            return json;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 将Bean转为带有泛型的对象<br>
     * 使用示例 List&lt;ChrageQueryBean&gt; list =
     * JsonUtil.jsonStr2GenericObj(jsonStr, new
     * TypeReference&lt;List&lt;ChrageQueryBean&gt;&gt;() {});
     *
     * @param json - json字符串
     * @param type - jackson中定义的TypeReference对象
     *
     */
    public static <T> T jsonStr2GenericObj(String json, TypeReference<?> type) {
        T genericObj;
        try {
            genericObj = MAPPER.readValue(json, type);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return genericObj;
    }
    
    /**
     * 将泛型Bean转为Json字符串，并保留特殊设置<br>
     * 使用示例 String jsonStr = JsonUtil.genericObj2JsonStr(list, new
     * TypeReference&lt;List&lt;XPayBean&gt;&gt;() {});
     *
     * @param obj  - java对象
     * @param type - jackson中定义的TypeReference对象
     *
     */
    public static <T> String genericObj2JsonStr(T obj, TypeReference<?> type) {
        ObjectWriter writer = MAPPER.writerFor(type);
        StringWriter w = new StringWriter();
        try {
            writer.writeValue(w, obj);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return w.toString();
    }
    
    
    /**
     * 1、根据属性名从原json字符串获取子json字符串
     * 2、去掉首尾的双引号
     *
     * @param jsonStr   --原json字符串
     * @param fieldName --属性名
     */
    public static String get(String jsonStr, String fieldName) {
        String rtnStr = null;
        try {
            JsonNode node = MAPPER.readTree(jsonStr);
            if (node.get(fieldName) == null) {
                return null;
            }
            rtnStr = node.get(fieldName).toString();
            rtnStr = rtnStr.startsWith("\"") ? rtnStr.substring(1, rtnStr.length()) : rtnStr;
            rtnStr = rtnStr.endsWith("\"") ? rtnStr.substring(0, rtnStr.length() - 1) : rtnStr;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return rtnStr;
    }
}
